X680x0アセンブラ講座   #$12             《テキスト画面で遊ぼう》                 鎌田 誠
 今回は X68k のハードウェア寄りのお話です。それも一番身近なテキスト画面 の構造と使い方を研究しましょう。
    X68k の画面
 みなさんご存じのことだと思いますが、X68k のハードウェアによる画面表示 の機能は結構複雑です。と言っても、ゲーム専用機のようにハードウェアでポリ ゴン表示などができるわけではなく、透明色の指定が可能な多色ビットマップ (簡単に言えば形のある2次元の絵)を何枚も複雑に重ね合わせる作業をハード ウェアがやってくれるというものです。  X68k は画面が狭い(縦横のドット数が少ない)上に、表示に必要なデータの 転送速度と演算速度に余裕があるとは言えない(処理内容によっては絶対的に足 りない)ので、X68k の画面でできることは限られてしまいます。しかし、限ら れているからこそ、そのすべてを理解して上手に使いこなすという愉しみがある と言えるでしょう。
    テキストプレーン・テキストスクリーン・テキスト画面
 画面に表示されている情報そのものを記憶しているメモリを「VRAM」と言いま す。X68k はテキスト表示用の「テキスト VRAM」とグラフィック表示用の「グラ フィック VRAM」を別々に持っており、テキストとグラフィックを同時に表示す ることができます。  X68k のテキスト VRAM はいわゆる「水平型」と呼ばれる構造をしており、1 ドットあたり 1 ビットでサイズが 1024×1024 ドットの「テキストプレーン」 を 4 枚重ねることで 1 枚の「テキストスクリーン」を構成しています。テキス ト画面として表示できるテキストスクリーンは 1 枚だけです。4 枚のテキスト プレーンには 0~3 の番号が振られています。     テキストプレーンとテキストスクリーンとテキスト画面の関係          ┌──────┐          │プレーン3  │          │ ┌────┴─┐          │ │プレーン2  │          │ │ ┌────┴─┐          │ │ │プレーン1  │          │ │ │ ┌────┴─┐          └─┤ │ │プレーン0  │            │ │ │      │            └─┤ │      │              │ │      │              └─┤      │                │      │                └──────┘         └──────┬──────┘ ←テキストパレット                ↓             ┌──────┐             │      │             │      │             │ テキスト │             │ スクリーン │             │      │             │      │             └──────┘            └───┬───┘ ←ハードウェアスクロール                ↓              ┌───┐              │テキス│              │ト画面│              │   │              └───┘  テキストプレーンの大きさが 1024×1024 ドットなので、1 枚のテキストプレ ーンを記憶するために 1024×1024(bit)÷8(bit/byte)=128(KB) のテキスト VRAM が使われます。テキストプレーンは 4 枚あるので、テキスト VRAM 全体の 容量は 128(KB)×4=512(KB) です。  512KB のテキスト VRAM は、テキストプレーン 0→3 の順序でアドレス $00E00000~$00E7FFFF に割り付けられており、スーパーバイザモードで MPU か ら読み書きすることができます。     テキスト VRAM のアドレス配置    ┌────────────────────────────    │;テキストVRAM    │    .offset $00E00000    │TextPlane0:   .ds.w  1024*1024/16  ;テキストプレーン0    │TextPlane1:   .ds.w  1024*1024/16  ;テキストプレーン1    │TextPlane2:   .ds.w  1024*1024/16  ;テキストプレーン2    │TextPlane3:   .ds.w  1024*1024/16  ;テキストプレーン3  テキスト VRAM 内のビットの並び順は、テキストプレーンの左上隅から水平方 向に、VRAM の上位のビットから充填されます。Y 方向に 1 ドット進むと、アド レスは $80 だけ増えます。例えば、テキストプレーン 0 の左上隅に標準の半角 ROM フォントで「AB」と表示されているときのテキスト VRAM の内容は次のよう になります。             テキスト VRAM の内容の例     テキストプレーン0の左上隅     ┌─────────────────   アドレス 内容     │○○○○○○○○○○○○○○○○ → $00E00000 $0000 …     │○○○●○○○○●●●●●○○○ → $00E00080 $10F8 …     │○○●○●○○○○●○○○●○○ → $00E00100 $2844 …     │○●○○○●○○○●○○○○●○ → $00E00180 $4442 …     │●○○○○○●○○●○○○○●○ → $00E00200 $8242 …     │●○○○○○●○○●○○○○●○ → $00E00280 $8242 …     │●○○○○○●○○●○○○●○○ → $00E00300 $8244 …     │●○○○○○●○○●●●●○○○ → $00E00380 $8278 …     │●●●●●●●○○●○○○●○○ → $00E00400 $FE44 …     │●○○○○○●○○●○○○○●○ → $00E00480 $8242 …     │●○○○○○●○○●○○○○●○ → $00E00500 $8242 …     │●○○○○○●○○●○○○○●○ → $00E00580 $8242 …     │●○○○○○●○○●○○○●○○ → $00E00600 $8244 …     │●○○○○○●○●●●●●○○○ → $00E00680 $82F8 …     │○○○○○○○○○○○○○○○○ → $00E00700 $0000 …     │○○○○○○○○○○○○○○○○ → $00E00780 $0000 …     │                        :  なお、X68k のテキスト画面は 1 ドットあたり 1 ビットのテキストプレーン を何枚も重ねて 1 枚のテキストスクリーンを構成する「水平型」になっていま すが、グラフィック画面は 1 ドットあたり 4~16 ビットが割り当てられたグラ フィックプレーン 1 枚で 1 枚のグラフィックスクリーンを構成する「垂直型」 になっています。水平型は一度に扱う色数が少なくいテキストやウィンドウの表 示に適しており、垂直型は一度に扱う色数が多いグラフィックの表示に適してい ます。
    テキストパレット
 前述の通り、X68k のテキスト画面は 1 ドットあたり 1 ビット× 4 プレーン で構成されています。4 つのテキストプレーンの同じ座標にあるドットがテキス トスクリーン上の 1 ドットを構成しており、テキストプレーン 3→0 の順序で 1 ビットの値を上位から順にならべてできる 4 ビットの値(10 進数に換算する と0~15)がテキストスクリーン上のそのドットの「パレットコード」になりま す。このパレットコードをインデックスとして、「テキストパレットレジスタ」 から「カラーコード」が求められ、テキストスクリーン上のそのドットの色が決 定されます。  例えば、4 枚のテキストプレーンの同じ座標の内容がテキストプレーン 0 か ら順に 1,1,0,0 だった場合、その座標に表示されるカラーコードは次の図のよ うにして求められます。        テキストパレットからカラーコードが決定される   ┌──────┐   │プレーン3  │   │ ┌────┴─┐   │ │プレーン2  │   │ │ ┌────┴─┐   │ │ │プレーン1  │   │0│ │ ┌────┴─┐   └┰┤ │ │プレーン0  │    ┃│0│ │      │ ┌──────┬─────────┐    ┃└┰┤ │      │ │ パレット │  カラーコード  │    ┃ ┃│1│      │ │  コード  │  (値は標準値)  │    ┃ ┃└┰┤      │ ├───3210─┼16進数─G─R─B┤    ┃ ┃ ┃│1     │ │  0 (0000) │$0000  0  0  0│    ┃ ┃ ┃└┰─────┘ │  1 (0001) │$F83E  31  0 31│   ┏┻┳┻┳┻┳┻┓      │  2 (0010) │$FFC0  31 31  0│   ┃0┃0┃1┃1┠──────┼→ 3 (0011) │$FFFE  31 31 31│←   ┗━┻━┻━┻━┛      │  4 (0100) │$DE6C  27 25 21│                  │  5 (0101) │$DE6C  27 25 21│                  │  6 (0110) │$DE6C  27 25 21│                  │  7 (0111) │$DE6C  27 25 21│                  │  8 (1000) │$4022  8  0 17│                  │  9 (1001) │$4022  8  0 17│                  │ 10 (1010) │$4022  8  0 17│                  │ 11 (1011) │$4022  8  0 17│                  │ 12 (1100) │$4022  8  0 17│                  │ 13 (1101) │$4022  8  0 17│                  │ 14 (1110) │$4022  8  0 17│                  │ 15 (1111) │$4022  8  0 17│                  └──────┴─────────┘  テキストパレットレジスタは、アドレス $00E82200~ の 16 ワードに割り付 けられています。このレジスタはスーパーバイザモードで読み書きできます。     テキストパレットレジスタのアドレス配置    ┌────────────────────────────    │;テキストパレットレジスタ    │    .offset $00E82200    │TextPaletRegister:   .ds.w  16   ;テキストパレット0~15    │                    ;%GGGGG_RRRRR_BBBBB_I  なお、テキストパレットレジスタはスプライトのパレットブロック 0 のパレ ットレジスタと共用になっています。 ●テキストパレットを使って複数のサブスクリーンがあるように見せる  テキストパレットのカラーコードの割り当てを工夫することで、テキストスク リーンの中に複数のサブスクリーンがあってそれらに優先順位があるかのように 見せることが可能です。  上の表のカラーコードの標準値を見ると、テキストパレット 0~3 はそれぞれ 異なるカラーコードが設定されていますが、テキストパレット 4~7 および 8~15 にはそれぞれ共通のカラーコードが設定されていることがわかります。こ のように設定することで、一番手前がテキストプレーン 3 を使った青色のサブ スクリーン、その次がテキストプレーン 2 を使った白っぽいサブスクリーン、 一番奥がテキストプレーン 0 と 1 を使った黒、青、黄、白の 4 色のサブスク リーンがあるように見せているのです。X68k の標準のコンソールの環境では、 テキストの文字の形をテキストプレーン 0 と 1 に書き込み、マウスカーソルと 電卓とソフトウェアキーボードはテキストプレーン 2 でその形を塗り潰した上 でテキストプレーン 3 に枠や文字を書き込むという使い方になっています。
    テキスト画面のハードウェアスクロール
 テキストスクリーンは常に 1024×1024 ドットのサイズで保持されていますが、 その全体がいつも画面に表示されているわけではありません。例えば、画面モー ドを 768×512 ドットに設定しているときは、テキストスクリーンは全体のわず か 3/8 の領域しか画面に出ていないことになります。  テキストスクリーンのどの部分を画面に表示するかを決定するのが「テキスト スクロールレジスタ」です。画面に表示する範囲の左上隅のテキストスクリーン 上の座標をテキストスクロールレジスタに書き込むことで、テキストスクリーン の表示を全体的にずらすことができます。これをテキスト画面の「ハードウェア スクロール」と呼びます。テキストスクロールレジスタの内容を一定の速度で連 続的に変化させることで、テキストスクリーン全体が動いているように見せるこ とができます(テキストプレーン毎のスクロールはできません)。   画面サイズが 768×512 ドットでスクロール位置が 0,0 のとき(初期状態)         ┌──────────────┬────┐         │0,0          767,0│ 1023,0│         │              │    │         │              │    │         │              │    │         │     表示範囲     │    │         │              │    │         │              │    │         │              │    │         │0,511        767,511│    │         ├──────────────┘    │         │                   │         │                   │         │                   │         │                   │         │                   │         │                   │         │                   │         │                   │         │0,1023            1023,1023│         └────── テキストVRAM ──────┘     画面サイズが 512×512 ドットでスクロール位置が 128,256 のとき         ┌───────────────────┐         │0,0               1023,0│         │                   │         │                   │         │                   │         │  ┌─────────┐      │         │  │128,256  639,256│      │         │  │         │      │         │  │         │      │         │  │         │      │         │  │   表示範囲   │      │         │  │         │      │         │  │         │      │         │  │         │      │         │  │128,767  639,767│      │         │  └─────────┘      │         │                   │         │                   │         │                   │         │0,1023            1023,1023│         └────── テキストVRAM ──────┘  テキストスクロールレジスタの実体は CRTC のレジスタ R10~R11 です。これ はアドレス $00E80014~ の 2 ワードに割り付けられています。これらのレジス タはスーパーバイザモードで読み書きできます。     テキストスクロールレジスタのアドレス配置    ┌────────────────────────────    │;テキストスクロールレジスタ    │    .offset $00E80014    │TextScrollRegisterX:  .ds.w  1    ;テキストX方向スクロール    │TextScrollRegisterY:  .ds.w  1    ;テキストY方向スクロール    │  ハードウェアスクロールのサンプル ●ウェーブを実行する(キーを押すと終了) =非対応メニューです ◎ウェーブのプログラムを見る  画面のハードウェアスクロールの種類で、表示範囲がスクリーンの下端からは み出すとスクリーンの上端が表示されるものを「円筒スクロール」と呼びます。 円筒スクロールでなおかつ表示範囲がスクリーンの右端からはみ出すとスクリー ンの左端が表示されるものを「球面スクロール」と呼びます。X68k のテキスト 画面のハードウェアスクロールは円筒スクロール、グラフィック画面のハードウ ェアスクロールは球面スクロールになっています。  テキスト画面は円筒スクロールなので、テキストスクロールレジスタの設定に よって表示範囲がテキストスクリーンの下端からはみ出した部分にはテキストス クリーンの上端が表示されますが、右端からはみ出すと正常に表示されず画面が 乱れてしまいます(一定のルールで乱れるので無理矢理使おうと思えば使えない こともない)。このことから、テキストスクロールレジスタの設定値の範囲は、 X 方向は 0~1023-表示画面の横のドット数、Y 方向は 0~1023 ということにな ります。     画面サイズが 768×512 ドットでスクロール位置が 0,768 のとき         ┌──────────────┬────┐         │0,0          767,0│ 1023,0│         │     表示範囲     │    │         │      (下)      │    │         │0,255        767,255│    │         ├──────────────┘    │         │                   │         │                   │         │                   │         │                   │         │       テキストVRAM       │         │                   │         │                   │         │                   │         │                   │         ├──────────────┐    │         │0,768        767,768│    │         │     表示範囲     │    │         │      (上)     │ 1023, │         │0,1023       767,1023│  1023│         └──────────────┴────┘  SX-WINDOW の実画面モードはハードウェアスクロールを使って 1024×1024 ド ットのテキストスクリーンを目一杯有効に使っています。なお、標準のコンソー ルはテキストのスクロールをラスタコピーで行っており、標準のコンソールモー ドでテキスト画面のハードウェアスクロールが使われることはほとんどありませ ん。
    テキスト VRAM に対する CRTC の特殊機能
 テキスト VRAM は普通のメモリと違って CRTC の管理下にあり、MPU からテキ スト VRAM への書き込みは CRTC を経由して行われます。そのため、CRTC を使 って MPU からテキスト VRAM への書き込みに加工を施したり、CRTC が自分でテ キスト VRAM の内容をコピーするなどの特殊機能が用意されています。  テキスト VRAM に関する CRTC の特殊機能は、具体的には次の 3 つです。     ・同時アクセス     ・ビットマスク     ・ラスタコピー  続いて、それぞれの特殊機能について解説します。
    テキスト VRAM の同時アクセス
 CRTC の機能に「テキスト VRAM への 1 回の書き込みで複数のテキストプレー ンの同じ座標のデータを同時に書き換える」というものがあります。これが「テ キスト VRAM の同時アクセス」です。同時アクセスは CRTC のモードの設定で ON/OFF することができます。同時アクセス機能を ON にしている状態を「同時 アクセスモード」と呼びます。  前述のように、テキスト VRAM はアドレス $00E00000~$00E7FFFF に割り付け られており、スーパーバイザモードで MPU から直接書き換えることができます。 しかし、同時アクセスモードを ON にすると、テキスト VRAM への書き込みが一 旦 CRTC に横取りされて、あらかじめ設定しておいた複数のテキストプレーンに 対する同時書き込みに読み変えられます。この状態で MPU からテキスト VRAM 上のあるテキストプレーンのある座標に書き込もうとすると、テキストプレーン 番号(テキスト VRAM のアドレスで言うと bit17~18)が無視されて、代わりに あらかじめ指定しておいた複数のテキストプレーンの同じ座標にそのとき書き込 もうとしたデータが同時に書き込まれるのです。  同時アクセスを使うことで 1 枚のテキストプレーンへの書き込みと同じ所要 時間で複数のテキストプレーンに書き込むことができるので、例えば標準のコン ソールで白い文字を書くためにプレーン 0 とプレーン 1 の両方に文字のパター ンを書き込むときなどに同時アクセスが使用されています。また、複数のテキス トプレーンを同時にクリアするなどの処理にも同時アクセスを使うことができま す。   ・同時アクセスモードでないとき     move.w #$FFFF,$00E00000         → ($00E00000).w に $FFFF が書き込まれる   ・プレーン 2,3 への同時アクセスモードが設定されているとき     move.w #$FFFF,$00E00000         → $00E40000 と $00E60000 に同時に $FFFF が書き込まれる  同時アクセスモードの設定には、アドレス $00E8002A に配置されている CRTC のレジスタ R21 を使用します。R21 の bit8 をセットすると同時アクセスモー ドになり、bit4~7(それぞれテキストプレーン 0~3 に対応)で 1 をセットし たプレーンが同時アクセスの対象になります。     同時アクセス/ビットマスクモード設定レジスタのアドレス配置    ┌────────────────────────────    │;テキスト同時アクセス/ビットマスク設定レジスタ    │    .offset $00E8002A    │TextAccessControl:   .ds.w  1    ;テキスト同時アクセスモード設定    │                    ;bit4 テキストプレーン0(0=OFF,1=ON)    │                    ;bit5 テキストプレーン1(0=OFF,1=ON)    │                    ;bit6 テキストプレーン2(0=OFF,1=ON)    │                    ;bit7 テキストプレーン3(0=OFF,1=ON)    │                    ;bit8 テキスト同時アクセス(0=OFF,1=ON)    │                    ;bit9 テキストビットマスク(0=OFF,1=ON)    │TextBitMaskRegister:  .ds.w  1    ;ビットマスクレジスタ    │                    ;(1にしたビットは書き込まない)  同時アクセスはテキスト VRAM への書き込みに限って行われます。同時アクセ スモードを ON にしても、読み出しは通常通りアドレスで指定されたテキストプ レーンから読み出されます。MPU を使ってテキスト VRAM 内でデータの加工や転 送を行うとき、同時アクセスモードが設定されていると通常と結果が変わってし まうので注意が必要です。   ・同時アクセスモードでないとき     not.w  $00E00000         → $00E00000 の内容が 1 ビット毎に 0/1 反転される   ・プレーン 2,3 への同時アクセスモードが設定されているとき     not.w  $00E00000         → $00000000 の内容を 1 ビット毎に 0/1 反転した結果が           $00E40000 と $00E60000 に書き込まれる
    ビットマスク
 これも CRTC の特殊機能で、MPU からテキスト VRAM への書き込みに対して強 制的に一部のビットの書き込みを抑制するというものです。  テキスト VRAM は水平型で 1 枚のテキストプレーンの中では 1 バイトで 8 ドット分の情報を持っているので、MPU からの 1 回の書き込みで最低でも 8 ド ットを更新することになります。このままでは、8 ドットの中の一部のドットを 書き換えたくないときは「一旦テキスト VRAM から元のデータを読み出してその 一部を書き換えてテキスト VRAM に書き戻す」という処理が必要になってしまい ます。そこで、あらかじめ 16 ビット単位で書き換えたくないビットの位置を設 定しておくことで、テキスト VRAM に普通に書き込んでも一部のビットだけを書 き換えることができるようになっています。これが「ビットマスク」です。  ビットマスクは 16 ドット(1 ワード)単位で指定することができます。  ビットマスク機能は、同じマスクを連続して使うことができる場合に特に効果 を発揮します。例えば、テキスト画面上に縦線を表示する場合や、ボックスフィ ルの左右の端の表示、既に表示されているテキストに対する網掛けなどの処理に 適しています。  ビットマスクを使用するには、アドレス $00E8002E にあるビットマスクレジ スタ(CRTC のレジスタ R23)に 16 ビットの中で書き込みたくないビットを 1 にするようにマスクを設定し、アドレス $00E8002A の CRTC のレジスタ R21 の bit9 をセットします。     同時アクセス/ビットマスクモード設定レジスタのアドレス配置    ┌────────────────────────────    │;テキスト同時アクセス/ビットマスク設定レジスタ    │    .offset $00E8002A    │TextAccessControl:   .ds.w  1    ;テキスト同時アクセスモード設定    │                    ;bit4 テキストプレーン0(0=OFF,1=ON)    │                    ;bit5 テキストプレーン1(0=OFF,1=ON)    │                    ;bit6 テキストプレーン2(0=OFF,1=ON)    │                    ;bit7 テキストプレーン3(0=OFF,1=ON)    │                    ;bit8 テキスト同時アクセス(0=OFF,1=ON)    │                    ;bit9 テキストビットマスク(0=OFF,1=ON)    │    .offset $00E8002E    │TextBitMaskRegister:  .ds.w  1    ;ビットマスクレジスタ    │                    ;(1にしたビットは書き込まない)
    ラスタコピー
 テキストプレーンを縦に 4 ドットずつ 256 個に分割し、それぞれを「ラスタ ブロック」と呼ぶことにします。ラスタブロックには、テキストプレーンの上か ら順に 0~255 の番号を付けておきます。                ラスタブロック         ┌───────────────────┐         │0,0                  │         │      ラスタブロック0      │         │                1023,3│         ├───────────────────┤         │0,4                  │         │      ラスタブロック1      │         │                1023,7│         ├───────────────────┤         ~                   ~         ├───────────────────┤         │0,252                 │         │     ラスタブロック255      │         │               1023,255│         └───────────────────┘  1 水平帰線期間内に、指定された複数のテキストプレーンの指定されたラスタ ブロックの内容を、それぞれ同じテキストプレーンの別のラスタブロックにコピ ーすることができます。この機能をラスタコピーと呼びます。ラスタコピーも CRTC の特殊機能の 1 つです。  例えば、水平同期周波数が 31.5KHz の画面モード(標準の 768×512 ドット の場合など)の場合、1 水平同期期間は 1(raster)÷31500(raster/s)=31.75(μs) しかありません。ラスタコピーはこ の 1 水平同期期間に最大で 128(byte)×4(raster)×4(plane)=2048(byte) のデータをコピーできるわけで すから、ラスタコピーの転送速度は最大で 2048(byte)÷31.75(μs)=64.5(MB/s) となります(実際にはラスタコピーは水 平帰線期間内に行われるので転送速度はこれのさらに 3 倍以上速い)。ちなみ に 10MHz の MC68000 がノーウェイトのメモリ上でデータをコピーする場合の転 送速度は高々 2.5(MB/s) 程度、50MHz の MC68060 がノーウェイトのメモリ上で ライン転送しても高々 80(MB/s) 程度ですから、X68000 というハードウェアの 中ではラスタコピーは極端に速い転送であることがわかります。  ラスタコピー機能は、その高速性をいかしてコンソールのスクロールやクリア に使われています。  ラスタコピーを行うには、CRTC の R22 レジスタ($00E8002C)に「ソースラ スタブロック番号×256+デスティネーションラスタブロック番号」を設定し、 CRTC 動作ポート($00E80480)に $0008 を書き込むことで行います。ただし、 ラスタコピーは 1 水平帰線期間内に 1 回だけしか行うことができないので、 動作速度の異なる X68000 と X68030 の両方で確実に動作するようにするために はタイミングの取り方に注意する必要があります。例えば、X68000 の ROM の IOCS が持っているラスタコピールーチンは X68030 では正常に動作しません。  なお、ラスタコピーにも前述のビットマスクが効きます。  ラスタコピーのサンプル ●テキストクリアを実行する =非対応メニューです ◎テキストクリアのプログラムを見る ●アップスクロールを実行する(ESC で終了) =非対応メニューです ◎アップスクロールのプログラムを見る ●ダウンスクロール(その1)を実行する(ESC で終了) =非対応メニューです ◎ダウンスクロール(その1)のプログラムを見る ●ダウンスクロール(その2)を実行する(ESC で終了) =非対応メニューです ◎ダウンスクロール(その2)のプログラムを見る ●超低速スムーススクロールアップを実行する(ESC で終了) =非対応メニューです ◎超低速スムーススクロールアップのプログラムを見る ●超低速スムーススクロールダウンを実行する(ESC で終了) =非対応メニューです ◎超低速スムーススクロールダウンのプログラムを見る  ダウンスクロールのその1とその2の違いをじっくり研究してみて下さい。  超低速スムーススクロールは、ラスタコピーは本来 4 ドット単位でしか指定 できないのに 2 ドット単位でスムーススクロールしている(ように見える)と ころがミソです。
 ビットマスクのサンプルを用意する時間がなくなってしまいました。他にも X68000 で文字列を高速表示する方法など、ネタはいくつかあるのですが、それ らはまた次の機会に。 (EOF)